"""
Case Type   : 资源池化
Case Name   : 资源池化环境下,无业务压力,踢出主节点,switchover -A主备切换
Create At   : 2024.4.18
Owner       : songshixuan
Description :
    1、查看集群状态 cm_ctl query -Cv
    2、停止原主节点 cm_ctl stop -n 1 -D xxx/dn1
    3、主节点执行switchover -A切换主备节点
    4、再次查看切换后集群状态 cm_ctl query -Cv
    5、任意备节点执行switchover -A切换
    6、再次查看切换后集群状态 cm_ctl query -Cv
    7、恢复集群原始状态
Expect      :
    1、集群状态正常，数据库节点状态正常
    2、停止原主节点成功
    3、switchover -A执行成功
    4、集群状态正常,任意备节点切换为主节点，原主节点降为备节点
    5、switchover -A执行成功
    6、集群状态正常,主备节点发生变化,具体节点状态以当前实际切换为准
    7、恢复集群原始状态成功,集群状态正常
History     :
"""

import os
import unittest
import time
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import macro

Primary_SH = CommonSH('PrimaryDbUser')
Standby1_SH = CommonSH('Standby1DbUser')
Standby2_SH = CommonSH('Standby2DbUser')


@unittest.skipIf(3 != Primary_SH.get_node_num(), '非1+2环境不执行')
class SharedStorage(unittest.TestCase):

    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.constant = Constant()
        self.s1_comsh = CommonSH('Standby1DbUser')

    def test_shared_storage(self):
        text = '-----step1:查看集群状态; expect:集群状态正常-----'
        self.log.info(text)

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)

        text = '-----step2:停止原主节点; expect:停止成功-----'
        self.log.info(text)

        stopdn = Primary_SH.exec_cm_ctl(mode='stop',
                                        param='-n 1',
                                        path=f'-D {macro.DB_INSTANCE_PATH}')
        self.log.info(stopdn)
        self.assertIn(self.constant.cm_stop_instance_success_msg, stopdn,
                      '执行失败' + text)
        self.log.info('sleep until the stop already') 
        time.sleep(40)
        text = '-----step3:查看集群状态;expect:集群状态异常，原主节点Down-----'
        self.log.info(text)
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cvipd')
        self.log.info(status)
        self.assertIn('cluster_state   : Degraded', status, '执行失败' + text)
        res1 = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        res2 = status.splitlines()[-1].split('|')[1].split('6002')[-1]
        res3 = status.splitlines()[-1].split('|')[2].split('6003')[-1]
        self.assertIn('P Down    Manually stopped', res1, '执行失败' + text)
        if 'S Primary Normal' in res2:
            # 此时原备2应该为备
            self.assertIn('S Standby Normal', res3, '执行失败' + text)
        else:
            # 否则原备1应该为备，原备2应该为主
            self.assertIn('S Standby Normal', res2, '执行失败' + text)
            self.assertIn('S Primary Normal', res3, '执行失败' + text)

        text = '-----step4:主节点执行switchover -A切换; expect:执行成功-----'
        self.log.info(text)

        switch = self.s1_comsh.exec_cm_ctl(mode='switchover', param='-A')
        self.log.info(switch)
        self.assertIn(self.constant.cm_switchover_A_success_msg, switch,
                      '执行失败' + text)
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Degraded', status, '执行失败' + text)
        res1 = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        res2 = status.splitlines()[-1].split('|')[1].split('6002')[-1]
        res3 = status.splitlines()[-1].split('|')[2].split('6003')[-1]
        self.assertIn('P Down    Manually stopped', res1, '执行失败' + text)
        if 'S Primary Normal' in res2:
            # 此时原备2应该为备
            self.assertIn('S Standby Normal', res3, '执行失败' + text)
        else:
            # 此时原备1应该为备，原备2应该为主
            self.assertIn('S Standby Normal', res2, '执行失败' + text)
            self.assertIn('S Primary Normal', res3, '执行失败' + text)

        text = '-----step5:集群重新启动; expect:执行成功-----'
        self.log.info(text)
        startdn = Primary_SH.exec_cm_ctl('start')
        self.log.info(startdn)
        self.assertIn(self.constant.cm_start_success_msg, startdn,
                      '拉起dn节点失败')
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)
        res1 = status.splitlines()[-1].split('|')[0].split('6001')[-1]
        res2 = status.splitlines()[-1].split('|')[1].split('6002')[-1]
        res3 = status.splitlines()[-1].split('|')[2].split('6003')[-1]
        self.assertIn('P Standby Normal', res1, '执行失败' + text)
        if 'S Primary Normal' in res2:
            # 此时原备2应该为备
            self.assertIn('S Standby Normal', res3, '执行失败' + text)
        else:
            # 此时原备1应该为备，原备2应该为主
            self.assertIn('S Standby Normal', res2, '执行失败' + text)
            self.assertIn('S Primary Normal', res3, '执行失败' + text)

    def tearDown(self):
        text = '-----step6:抓一下standby1异常堆栈; expect:成功-----'
        self.log.info(text)
        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        status = Primary_SH.check_cluster_core_status(status, wait_times=600)
        self.log.info(status)
        # 2024-6-3 新增gstack抓取功能，当检测到异常的时候先粗暴的抓一下堆栈
        queryCmd = Standby1_SH.exec_cmd_under_user("ps -ux | grep app/bin/gaussdb | grep -v -- '--color'")
        pid = queryCmd.split()[1]
        gsStackGaussdb = Standby1_SH.exec_cmd_under_user("gstack " + pid)
        self.log.info(gsStackGaussdb)
        queryCmd = Standby1_SH.exec_cmd_under_user("ps -ux | grep app/bin/dssserver | grep -v -- '--color'")
        pid = queryCmd.split()[1]
        gsStackDssServer = Standby1_SH.exec_cmd_under_user("gstack " + pid)
        self.log.info(gsStackDssServer)
        
        text = '-----step7:抓一下standby2异常堆栈; expect:成功-----'
        self.log.info(text)
        # 2024-6-3 新增gstack抓取功能，当检测到异常的时候先粗暴的抓一下堆栈
        queryCmd = Standby2_SH.exec_cmd_under_user("ps -ux | grep app/bin/gaussdb | grep -v -- '--color'")
        pid = queryCmd.split()[1]
        gsStackGaussdb = Standby2_SH.exec_cmd_under_user("gstack " + pid)
        self.log.info(gsStackGaussdb)
        queryCmd = Standby2_SH.exec_cmd_under_user("ps -ux | grep app/bin/dssserver | grep -v -- '--color'")
        pid = queryCmd.split()[1]
        gsStackDssServer = Standby2_SH.exec_cmd_under_user("gstack " + pid)
        self.log.info(gsStackDssServer)
        
        text = '-----step8:恢复环境为初始集群状态; expect:成功-----'
        self.log.info(text)
        
        status = Primary_SH.exec_cm_ctl(mode='stop', param='')
        self.log.info(status)
        self.assertIn('successfully.', status, '执行失败' + text)

        status = Primary_SH.exec_cm_ctl(mode='start', param='')
        self.log.info(status)
        self.assertIn('successfully.', status, '执行失败' + text)
        
        recovery = Primary_SH.exec_cm_ctl(mode='switchover', param='-a')
        self.log.info(recovery)
        self.assertIn(self.constant.cm_switchover_success_msg, recovery,
                      '执行失败' + text)

        status = Primary_SH.exec_cm_ctl(mode='query', param='-Cv')
        self.log.info(status)
        self.assertIn('cluster_state   : Normal', status, '执行失败' + text)
        self.assertIn('P Primary Normal',
                      status.splitlines()[-1].split('|')[0].split('6001')[-1],
                      '执行失败' + text)
        self.assertIn('S Standby Normal',
                      status.splitlines()[-1].split('|')[1].split('6002')[-1],
                      '执行失败' + text)
        self.log.info(f'-----{os.path.basename(__file__)} end-----')

